Heroku の仕組み
最終更新日 2025年02月20日(木)
Table of Contents
ここでは、Heroku の仕組みに関する高度で技術的な内容を説明します。Heroku プラットフォームでアプリケーションを作成、設定、デプロイ、実行するときに必要となる多くの概念をまとめています。
「スターターガイド」のいずれかのチュートリアルを実施すると、 このドキュメントの概念をより具体的に理解できます。
このドキュメントは上から順に読み進めてください。このドキュメントでは、流れに沿って説明するために、プラットフォームに関する概念を少しずつ紹介し、段階を追って改訂していきます。
最後のセクションでは、すべての定義を Heroku のデプロイ時とランタイムの視点に分けてまとめています。
アプリとは
Heroku では、Rugy、Node.js、Java、Python、Clojure、Scala、Go、PHP、.NET で作成されたアプリのデプロイ、実行、管理を行うことができます。
アプリとは、上記の言語のいずれかで作成されたソースコード、場合によってはフレームワーク、そしてアプリケーションをビルドして実行するために必要な追加の依存関係をビルドシステムに指示するいくつかの依存関係の説明の集まりです。
用語 (暫定): アプリはソースコードと依存関係の説明で構成されています。
依存関係のメカニズムは言語によって異なります。Ruby では Gemfile
、Python では requirements.txt
、Node.js では package.json
、Java では pom.xml
などです。
アプリのソースコードと依存関係ファイルでは、Heroku プラットフォームでアプリケーションをビルドして実行可能なものを作成するのに十分な情報を提供する必要があります。
実行内容を明確にする
Heroku でアプリを実行するために多くの変更を加える必要はありませんが、アプリのどの部分が実行可能であるかをプラットフォームに伝える必要があります。
一部の定着しているフレームワークを使用すれば、Heroku によって実行可能部分が認識されます。たとえば、Ruby on Rails では通常 rails server
、Django では python <app>/manage.py runserver
、Node.js では package.json
内の main
です。
用語: Procfile では、プロセスタイプ (実行する名前付きコマンドのリスト) を定義します。
その他のアプリの場合は、ソースコードに付随するテキストファイル (Procfile) で実行可能なものを明示的に宣言する必要があります。各行で、プロセスタイプ - ビルドされたアプリケーションに対して実行できる名前付きコマンドを宣言します。たとえば、次のようになります。
web: java -jar lib/foobar.jar $PORT
queue: java -jar lib/queue-processor.jar
このファイルでは、web
プロセスタイプを宣言し、これを動作させるために実行する必要があるコマンド (java -jar lib/foobar.jar $PORT
) を提供します。また、queue
プロセスタイプと、それに対応するコマンドも宣言されます。
ここで、前回のアプリの定義を改訂して、Procfile の文言を追加します。
用語: アプリは、ソースコード、依存関係の説明、Procfile で構成されています。
Heroku は多言語プラットフォームです。すべての言語にわたって同様の方法で、つまり依存関係と Procfile を利用して、アプリケーションのビルド、実行、スケールを行うことができます。Procfile によりアプリケーションのアーキテクチャの側面が公開され (上記の例では、アプリケーションへの 2 つのエントリポイントがある)、このアーキテクチャにより、たとえば各部分を個別にスケールすることなどができます。「Heroku のアプリケーションを設計する」は、Heroku で実行するアプリケーションに役立つアーキテクチャの原則に関する優れたガイドです。
アプリケーションをデプロイする
Git は、多くの開発者がソースコードの管理やバージョン管理に使用している、強力な分散型バージョン管理システムです。Heroku プラットフォームでは、アプリケーションをデプロイするための主な手段として Git を使用します。ソースコードを Heroku に転送する方法は、ほかにも API 経由などの方法があります。
Heroku でアプリケーションを作成すると、新しい Git リモート (通常は heroku
という名前) がアプリケーションのローカル Git リポジトリに関連付けられます。
結果として、コードのデプロイには git push
を使用しますが、デプロイ先は heroku
リモートになります。
$ git push heroku main
用語: アプリケーションのデプロイとは、Git か GitHub を使用して、または API 経由で、Heroku にアプリケーションを送信することです。
アプリケーションをデプロイする方法は、ほかにもたくさんあります。たとえば、新しい各プルリクエストが独自の新しいアプリケーションに関連付けられるように、GitHub インテグレーションを有効にすることができます。これにより、あらゆる種類の継続的なインテグレーションシナリオが実現されます。また、Heroku API を使用して、アプリのビルドとリリースを行うこともできます。
デプロイとは、アプリケーションをローカルシステムから Heroku に移動することを意味します。Heroku ではアプリをデプロイする方法を複数用意しています。
アプリケーションをビルドする
Heroku プラットフォームにソースコードが渡されると、ソースアプリケーションのビルドが開始されます。通常、ビルドの仕組みは言語ごとに異なりますが、基本的なパターンは同じです。通常は、指定された依存関係を取得し、スタイルシートの処理やコードのコンパイルなど、必要なアセットを作成します。
上級: buildpack では、アプリケーション、アプリケーションの依存関係、言語ランタイムからビルドアーティファクトが生成されます。buildpack はオープンソースで、これを使うことにより、Heroku をほかの言語やフレームワークに拡張することができます。
たとえば、ビルドシステムに Rails アプリケーションが渡されると、Gemfile で指定されているすべての依存関係が取得され、アセットパイプラインに基づいてファイルが生成されます。Java の場合は、Maven を使用してバイナリライブラリの依存関係が取得され、バイナリライブラリと一緒にソースコードがコンパイルされて、実行する JAR ファイルが生成されます。
アプリケーションのソースコードは、取得された依存関係、ビルドフェーズの出力 (生成されたアセットやコンパイルされたコードなど)、言語やフレームワークと共に、ビルドアーティファクトにまとめられます。
用語: 「ビルドアーティファクト」という用語は、両方の種類の世代固有アーティファクトを説明するために使用されます。
- Cedar 世代のアプリのビルドアーティファクトは slug です。slug は、ソース、取得された依存関係、言語ランタイム、およびビルドシステムのコンパイル/生成後の出力 (実行できる状態) のバンドルです。
- Fir 世代のアプリのビルドアーティファクトは、Cloud Native Buildpack によって生成された Open Container Initiative (OCI) 画像です。
ビルドアーティファクトは、アプリケーションの実行時における基本的な要素です。実行可能な状態にコンパイルされ、まとめられたアプリと、実行内容の指示 (Procfile) が含まれています。
dyno でアプリケーションを実行する
Heroku は Procfile で指定されたコマンドを、ビルドアーティファクトがあらかじめロードされた dyno 上で実行することにより、アプリケーションを起動します。より正確には、使用するのはリリースです。これはビルドアーティファクトおよびこのガイドでまだ定義されていないいくつかの項目 (環境設定とアドオン) を拡張します。
実行中の dyno は、ファイルシステム内にビルドアーティファクトを格納する、軽量で安全性が高い、仮想化された Unix コンテナのようなものです。
用語: dyno は、アプリケーションの実行に必要な環境を提供する、分離、仮想化された Unix コンテナです。
一般的に、初めてアプリケーションをデプロイする場合、Heroku では 1 つの Web dyno が自動的に実行されます。つまり、dyno が起動され、ビルドアーティファクトがロードされて、web
プロセスタイプに関連付けられたコマンドが Procfile 内で 実行されます。
一度に実行する dyno の数を制御できます。前に説明した Procfile を例にとると、次のようにして 5 つの dyno (web プロセスタイプが 3 つ、queue プロセスタイプが 2 つ) を起動できます。
$ heroku ps:scale web=3 queue=2
アプリケーションの新しいバージョンをデプロイすると、現在実行中の dyno がすべて強制終了され、既存の Dyno formation を維持したまま、起動する (新しいリリースを使用した) 新しい dyno に置き換えられます。
用語: アプリの Dyno formation とは現在実行中の dyno の総数を、スケール済みのさまざまなプロセスタイプに分けたものです。
実行中の状況を把握するには、どの dyno でどのプロセスタイプが実行されているかを確認するだけで済みます。
$ heroku ps --app app-name
== web: 'java lib/foobar.jar $PORT'
web.1: up 2013/02/07 18:59:17 (~ 13m ago)
web.2: up 2013/02/07 18:52:08 (~ 20m ago)
web.3: up 2013/02/07 18:31:14 (~ 41m ago)
== queue: `java lib/queue-processor.jar`
queue.1: up 2013/02/07 18:40:48 (~ 32m ago)
queue.2: up 2013/02/07 18:40:48 (~ 32m ago)
dyno はアプリケーションを拡張する重要な手段でもあります。この例では、アプリが正しく設計されているため、web と queue の Worker dyno を個別に拡張できます。
環境設定
アプリの設定とは、環境 (ステージング環境、本番環境、開発環境など) によって変わる可能性があるすべてのものです。この設定には、データベース、資格情報、アプリケーションに特定の情報を提供する環境変数などのバッキングサービスなどが含まれます。
Heroku では、カスタマイズ可能な設定でアプリケーションを実行できます。設定はアプリケーションコードの外部にあり、独立して変更できます。
アプリの設定は環境設定に保存されます。たとえば、アプリケーションの暗号化鍵を設定する方法は、次のとおりです。
$ heroku config:set ENCRYPTION_KEY=my_secret_launch_codes
Adding config vars and restarting demoapp... done, v14
ENCRYPTION_KEY: my_secret_launch_codes
用語: 環境設定 には、ソースコードとは関係なく変更できる、カスタマイズ可能な設定データが格納されます。この設定は、環境変数を通じて、実行中のアプリケーションに公開されます。
ランタイムではすべての環境設定が環境変数として公開されるため、プログラムで簡単に抽出できます。上記の環境設定を使用してデプロイされた Ruby アプリケーションは、ENV["ENCRYPTION_KEY"]
を呼び出すことで暗号化鍵にアクセスできます。
アプリケーション内のすべての dyno が、ランタイムで同じ一連の環境設定にアクセスできる必要があります。
リリース
この記事の前半で、dyno でアプリケーションを実行するときには、Heroku プラットフォームで dyno にビルドアーティファクトの最新バージョンがロードされると説明しました。これをさらに詳しく説明する必要があります。実際には、ビルドアーティファクトと、アプリケーションに割り当てた環境設定がロードされます。この 2 つを組み合わせたものをリリースと呼びます。
用語 (暫定): リリースとは、アプリのビルドアーティファクトと環境設定を記録する追加専用の台帳です。
すべてのリリースが追加専用の台帳に自動的に保持されるため、アプリケーションや複数のリリースの管理が簡単になります。リリースのデプロイに関する追跡記録を確認するには、heroku releases
コマンドを使用します。
$ heroku releases
== demoapp Releases
v103 Deploy 582fc95 jon@heroku.com 2013/01/31 12:15:35
v102 Deploy 990d916 jon@heroku.com 2013/01/31 12:01:12
デプロイメッセージの横にある番号 (たとえば、582fc95
) は、Heroku にデプロイしたリポジトリのコミットハッシュに一致します。
アプリケーションの新しいバージョンをデプロイするたびに、新しいビルドアーティファクトが作成され、リリースが生成されます。
Heroku にはアプリケーションの以前のリリースが保管されているので、簡単にロールバックして、以前のリリースをデプロイすることができます。
$ heroku releases:rollback v102
Rolling back demoapp... done, v102
$ heroku releases
== demoapp Releases
v104 Rollback to v102 jon@heroku.com 2013/01/31 14:11:33 (~15s ago)
v103 Deploy 582fc95 jon@heroku.com 2013/01/31 12:15:35
v102 Deploy 990d916 jon@heroku.com 2013/01/31 12:01:12
ソースの変更か設定の変更かに関係なく、アプリケーションに対して重要な変更を行うと、新しいリリースが作成されます。
リリースとは、Heroku でアプリケーションの設定 (環境設定) を、アプリケーションのソース (ビルドアーティファクトにパッケージ化されている) とは独立して変更できる仕組みであり、リリースはそれらを結び付ける役割を果たします。アプリケーションに関連付けられている一連の環境設定を変更するたびに、新しいリリースが生成されます。
Dyno Manager
Heroku プラットフォームの一部である Dyno Manager により、dyno の継続的な実行が維持されます。たとえば、dyno を少なくとも 1 日に 1 回、または Dyno Manager が、実行中のアプリケーションの障害 (メモリ不足の例外など) や、dyno を物理的に新しい場所に移動する必要があるような基盤となるハードウェアの問題を検知するたびに、再起動するように設定できます。
用語: Heroku プラットフォームの Dyno Manager は、Heroku で実行中のすべてのアプリケーションの dyno を管理します。
dyno の再起動は、(特段ほかの設定がない限り) 定期的に透過的かつ自動的に行われ、ログに記録されます。
用語: eco
dyno タイプを使用するアプリケーションは、スリープするか、ゼロにスケールされます。スリープ中のアプリケーションが HTTP トラフィックを受信するとスリープは解除されますが、数秒の遅延が発生します。
ほかのいずれかの dyno タイプを使用すると、スリープしないようにすることができます。
Heroku でアプリケーションの管理と実行が行われるため、オペレーティングシステムやほかの内部システムの設定を管理する必要はありません。One-off dyno は、入力 / 出力をローカルのターミナルに接続して実行できます。One-off dyno は、データベースの設定など、共有リソースの状態を変更する管理タスクを (多くの場合、スケジューラーを通じて定期的に) 実行するために使用することもできます。
用語: One-off dyno は、入力 / 出力をローカルのターミナルに接続して実行できる一時的な dyno です。これらには最新のリリースがロードされます。
One-off dyno を作成して接続する最も簡単な方法は、次のとおりです。
$ heroku run bash
Running `bash` attached to terminal... up, run.8963
~ $ ls
この方法により、新しい dyno が迅速に起動され、リリースがロードされた後、bash
コマンドが実行されて、Unix シェルを使用できるようになります (前述のとおり、dyno は事実上、分離、仮想化された Unix コンテナです)。セッションを終了するか、アイドル状態が一定の時間続くと、dyno は削除されます。
ある dyno で行ったファイルシステムへの変更は、ほかの dyno には反映されません。また、この変更は別のデプロイや dyno の再起動では無効になります。より適切でスケーラブルな方法は、データベースやキューなどの共有リソースを使用することです。
用語: 各 dyno には、最新リリースの新しいコピーが含まれる、独自の一時的なファイルシステムがあります。このファイルシステムは一時的なスクラッチパッドとして使用できますが、ファイルシステムへの変更はほかの dyno に反映されません。
dyno のファイルシステムの一時的という特性は、上記のコマンドで確認できます。heroku run bash
(dyno 上の Unix シェル) を実行して One-off dyno を作成し、その dyno でファイルを作成してから、セッションを終了すると、その変更は消滅します。同じアプリケーション内の dyno であっても、すべての dyno は分離されており、セッションが終了すると、dyno は強制終了されます。新しい dyno は、ほかの dyno の状態を継承するのではなく、常にビルドアーティファクトから作成されます。
アドオン
アプリケーションは、通常、アドオンを利用して、データベース、キューイングとキャッシングのシステム、ストレージ、メールサービスなどのバッキングサービスを提供します。アドオンは、Heroku やサードパーティからサービスとして提供され、アドオンの大規模なマーケットプレイスがあるため、そこから選択することができます。
Heroku では、アドオンは接続されたリソースとして扱われます。アドオンのプロビジョニングとは、アドオンマーケットプレイスからアドオンを選択して、自分のアプリケーションに接続することです。
たとえば、Heroku Key-Value Store のバッキングストアアドオンをアプリケーションに追加する方法は、次のとおりです。
$ heroku addons:create heroku-redis:mini
dyno ではファイルの状態が共有されないため、一種のストレージを提供するアドオンは、通常、アプリケーション内の dyno 間の通信手段として使用されます。たとえば、Key-Value Store または Postgres をキューのバッキングメカニズムとして使用することができ、web プロセスタイプの dyno ではそのキューにジョブリクエストをプッシュでき、queue プロセスタイプの dyno ではそのキューからジョブリクエストをプルできます。
アドオンサービスプロバイダーはサービスを担当し、アプリケーションへのインターフェースは、多くの場合、環境設定を通じて提供されます。この例では、アドオンをプロビジョニングすると REDIS_URL
が自動的にアプリケーションに追加されます。たとえば、次のように、URL を通じてサービスに接続するコードを書くことができます。
uri = URI.parse(ENV["REDIS_URL"])
REDIS = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
用語: Add-on は、簡単にアプリケーションに接続できて機能を拡張する、サードパーティの専門付加価値クラウドサービスです。
アドオンは環境設定のようにアプリケーションに関連付けられるため、前回のリリースの定義は改訂する必要があります。アプリケーションのリリースは、単なるアプリケーションのビルドアーティファクトと環境設定ではありません。ビルドアーティファクト、環境設定に加え、プロビジョニングされた一連のアドオンが含まれます。
用語: リリースは、アプリケーションのビルドアーティファクト、環境設定、アドオンを記録する追加専用の台帳です。Heroku では、作成されるリリースの追加専用の台帳が管理されます。
環境設定のように、アドオンの追加、削除、または変更を行うたびに、新しいリリースが作成されます。
ログと監視
Heroku では、ログはタイムスタンプ付きイベントのストリームとして扱われ、すべての dyno で実行中のすべてのプロセスから生成されたログと、Heroku プラットフォームのコンポーネントから生成されたログのストリームが Logplex (高パフォーマンスのリアルタイムログ配信システム) に順にまとめられます。
すべてのプラットフォームコンポーネントと dyno のログを簡単に確認できます。
$ heroku logs
2013-02-11T15:19:10+00:00 heroku[router]: at=info method=GET path=/articles/custom-domains host=mydemoapp.heroku.com fwd=74.58.173.188 dyno=web.1 queue=0 wait=0ms connect=0ms service=1452ms status=200 bytes=5783
2013-02-11T15:19:10+00:00 app[web.2]: Started GET "/" for 1.169.38.175 at 2013-02-11 15:19:10 +0000
2013-02-11T15:19:10+00:00 app[web.1]: Started GET "/" for 2.161.132.15 at 2013-02-11 15:20:10 +0000
上記の例では、タイムスタンプ付きの 3 つのログエントリが表示されています。1 つ目は Heroku のルーターから、残りの 2 つは web プロセスタイプを実行中の 2 つの dyno からのログエントリです。
用語: Logplex には、アプリのすべての実行中の dyno からのログエントリと、ルーターなどのほかのコンポーネントからのログエントリが自動的に順にまとめられるので、アクティビティを 1 か所で確認することができます。
1 つの dyno からログに入り、チャネルを開いたままにして、以降のイベントをリッスンすることもできます。
$ heroku logs --ps web.1 --tail
2013-02-11T15:19:10+00:00 app[web.1]: Started GET "/" for 1.169.38.175 at 2013-02-11 15:19:10 +0000
単にパフォーマンス上の理由で、Logplex では、限られたバッファのログエントリのみ保管されています。ログエントリ、および実行時のメール通知などのアクションイベントを保持するには、ログドレイン (Logplex からの出力を受信するための API) と連動する Logging Add-on を使用します。
HTTP ルーティング
Dyno formation に応じて、dyno の一部は web
プロセスタイプに関連付けられたコマンドを実行し、また一部は、ほかのプロセスタイプに関連付けられたほかのコマンドを実行します。
web
という名前のプロセスタイプを実行する dyno は、ある意味でほかのすべての dyno とは異なり、HTTP トラフィックを受信します。Heroku の HTTP ルーター は、受信リクエストを、実行中のすべての Web dyno 上のアプリケーションに分散します。
そのため、Web トラフィックを処理するためにアプリの処理能力をスケールするには、Web dyno の数をスケールします。
$ heroku ps:scale web+5
Heroku では、ランダム選択アルゴリズムを使用して、Web dyno 間で HTTP リクエストのロードバランスを行います。このルーティングは、HTTP トラフィックと HTTPS トラフィックの両方を処理します。複数の同時接続と、タイムアウト処理もサポートされています。
まとめ
この記事で説明した概念は、アプリケーションの開発とデプロイに関するものと、デプロイ後の Heroku プラットフォームとアプリケーションのランタイム処理に関するものの 2 種類に大別されます。
次の 2 つのセクションでは、プラットフォームのメインコンポーネントを 2 種類に分けて振り返ります。
デプロイ
- アプリは、ソースコード、依存関係の説明、Procfile で構成されています。
- Procfile では、プロセスタイプ (実行する名前付きコマンドのリスト) を定義します。
- アプリケーションのデプロイとは、Git か GitHub を使用して、または API 経由で、Heroku にアプリケーションを送信することです。
- buildpack では、アプリケーション、アプリケーションの依存関係、言語ランタイムからビルドアーティファクトが生成されます。
- Cedar 世代のアプリのビルドアーティファクトは slug です。slug は、ソース、取得された依存関係、言語ランタイム、およびビルドシステムのコンパイル / 生成後の出力 (実行できる状態) のバンドルです。
- Fir 世代のアプリの実行可能バンドルは OCI イメージです。
- 環境設定には、ソースコードとは独立して変更できる、カスタマイズ可能な設定データが格納されます。この設定は、環境変数を通じて、実行中のアプリケーションに公開されます。
- アドオンは、アプリケーションに簡単にアタッチして機能を拡張できる、サードパーティの専門付加価値クラウドサービスです。
- リリースは、ビルドアーティファクト (アプリケーション)、環境設定、アドオンの組み合わせです。Heroku では、作成されるリリースの追加専用の台帳が管理されます。
ランタイム
- dyno は、アプリケーションの実行に必要な環境を提供する、分離、仮想化された Unix コンテナです。
- アプリケーションの Dyno formation とは現在実行中の dyno の合計数のことで、スケール済みのさまざまなプロセスタイプに分配されます。
- Dyno Manager は、Heroku で実行中のすべてのアプリケーションの dyno を管理します。
eco
dyno タイプを使用するアプリケーションは、アイドル状態が 30 分続くとスリープします。別の dyno タイプにスケールすると、スリープしないようにできます。- One-off dyno は、入力 / 出力をローカルのターミナルに接続して実行する一時的な dyno です。この dyno には最新のリリースがロードされます。
- 各 dyno には、最新リリースの新しいコピーが含まれる、独自の一時的なファイルシステムがあります。このファイルシステムは一時的なスクラッチパッドとして使用できますが、ファイルシステムへの変更はほかの dyno に反映されません。
- Heroku ではアプリの実行中のすべての dyno からのログエントリと、ルーターなどのほかのコンポーネントが自動的にまとめられるため、アクティビティを 1 か所で確認することができます。
- アプリケーションのスケールとは、各プロセスタイプの dyno の数を変更することです。
次のステップ
- 「スターターガイド」のいずれかのチュートリアルを実施して、このドキュメントの概念をより具体的に理解します。
- 「Architecting Applications for Heroku」(Heroku のアーキテクチャ設計) を参照して、Heroku のアーキテクチャを活用したスケーラブルなアプリを構築する方法を理解します。